package main

import (
	"context"
	"earn/persistence"
	"fmt"
	"math/rand"
	"strconv"
	"strings"
	"sync"
	"time"

	"gitee.com/hacker61/go-binance/v2"
	"gitee.com/hacker61/go-binance/v2/spider"
)

var (
	binanceClient *binance.Client
	spiderClient  *spider.Client
	ppersistence  persistence.Persistence
)

func main_init() {
	binanceClient = binance.NewClient("", "")
	spiderClient = binance.NewOKEXSpiderClient()
	ppersistence = persistence.PersistenceMysql{}.Init(conf.MysqlOpt.Host, conf.MysqlOpt.Port, conf.MysqlOpt.User, conf.MysqlOpt.Passwd, conf.MysqlOpt.DBName)
}

func init() {
	conf_init()
	logger_init()
	main_init()
	futures_init()
}

func processActivityList() {
	getServiceListService := spiderClient.NewOKEXGetServiceListService()
	res, err := getServiceListService.Do(context.Background())
	if err != nil {
		Error.Println(err)
		return
	}
	// 查询当前数据库中存在的活动币种
	actMap := make(map[string][]persistence.OKEXActivityInfo)
	actList, err := ppersistence.GetActivityList()
	if err == nil {
		for _, actInfo := range actList {
			if _, bOK := actMap[actInfo.Coin]; !bOK {
				actMap[actInfo.Coin] = make([]persistence.OKEXActivityInfo, 0)
			}
			actMap[actInfo.Coin] = append(actMap[actInfo.Coin], *actInfo)
		}
	}
	deleteCoin := make(map[string]struct{})
	insertCoin := make(map[string][]*persistence.OKEXActivityInfo)
	for _, serv := range res {
		Debug.Println(*serv)
		_, bOk := actMap[serv.Unit]
		if serv.Status == 3 && bOk {
			deleteCoin[serv.Unit] = struct{}{}
		} else if serv.Status == 1 || serv.Status == 2 {
			info := new(persistence.OKEXActivityInfo)
			info.Coin = serv.Unit
			info.SumHold = serv.SumHold
			info.MaxHold = serv.MaxHold
			info.MinHold = serv.MinHold
			info.Period, _ = strconv.Atoi(serv.Period)
			info.Rate, _ = strconv.ParseFloat(strings.TrimRight(serv.Rate, "%"), 64)
			if _, bOK := insertCoin[info.Coin]; !bOK {
				insertCoin[info.Coin] = make([]*persistence.OKEXActivityInfo, 0)
			}
			insertCoin[info.Coin] = append(insertCoin[info.Coin], info)
		}
	}
	for coin := range deleteCoin {
		if _, bOK := insertCoin[coin]; bOK {
			delete(deleteCoin, coin)
		}
	}
	if len(deleteCoin) > 0 {
		Info.Printf("delete Coin: %v\n", deleteCoin)
		for delCoin := range deleteCoin {
			err = ppersistence.DeleteActivityInfo(delCoin)
			if err != nil {
				Error.Println(err)
			}
		}
	}
	if len(insertCoin) > 0 {
		for coin := range insertCoin {
			if _, bOK := actMap[coin]; bOK {
				delete(insertCoin, coin)
			}
		}
	}
	if len(insertCoin) > 0 {
		//var coin string
		//var period int
		for _, actInfos := range insertCoin {
			for _, actInfo := range actInfos {
				Info.Printf("NewCoin Activity: %v\n", actInfo)
				err = ppersistence.InsertActivityInfo(actInfo)
				if err != nil {
					Error.Println(err)
				}
				//coin = actInfo.Coin
				//period = actInfo.Period
			}
		}
		//sms_send(coin, fmt.Sprintf("%v", period))
		sms_send(fmt.Sprintf("%v", rand.Intn(10000)), "1")
	}
}

func processStakingList() {
	stakingList, err := spiderClient.NewOKEXGetEarnListService().ProductType(spider.OKEXProductTypeStaking).Do(context.Background())
	if err != nil {
		Error.Println(err)
		return
	}
	//Debug.Println(stakingList)
	// 查询当前数据库中存在的Staking币种
	stakingMap := make(map[string]map[int]persistence.OKEXStakingInfo)
	actList, err := ppersistence.GetStakingList()
	if err == nil {
		for _, actInfo := range actList {
			if _, bOK := stakingMap[actInfo.Coin]; !bOK {
				stakingMap[actInfo.Coin] = make(map[int]persistence.OKEXStakingInfo)
			}
			stakingMap[actInfo.Coin][actInfo.Period] = *actInfo
		}
	}

	//var coin string
	//var period int
	bHasChanged := false

	for _, serv := range stakingList {
		coinStaking, bOKCoin := stakingMap[serv.CurrencyName]
		if !bOKCoin && CheckFuturesInfo(serv.CurrencyName) {
			for _, staking := range serv.ProjectList {
				Debug.Println(staking)
				if staking.ProductStatus {
					info := new(persistence.OKEXStakingInfo)
					info.Coin = staking.Unit
					info.SumHold = staking.SumHold
					info.MaxHold = staking.MaxHold
					info.MinHold = staking.MinHold
					info.Period, _ = strconv.Atoi(staking.Period)
					info.Rate, _ = strconv.ParseFloat(strings.TrimRight(staking.Rate, "%"), 64)
					err = ppersistence.InsertStakingInfo(info)
					if err != nil {
						Error.Println(err)
					} else {
						//coin = staking.Unit
						//period, _ = strconv.Atoi(staking.Period)
						if info.Rate > float64(conf.NoticeRate) {
							bHasChanged = true
						}
						Info.Printf("NewCoin Staking: %v\n", info)
					}
				}
			}
		} else if CheckFuturesInfo(serv.CurrencyName) {
			for _, staking := range serv.ProjectList {
				Debug.Println(staking)
				stakingPeriod, _ := strconv.Atoi(staking.Period)
				if !staking.ProductStatus {
					if _, bOKPeriod := coinStaking[stakingPeriod]; bOKPeriod {
						err = ppersistence.DeleteStakingInfo(staking.Unit, stakingPeriod)
						if err != nil {
							Error.Println(err)
						}
					}
				} else {
					if _, bOKPeriod := coinStaking[stakingPeriod]; !bOKPeriod {
						info := new(persistence.OKEXStakingInfo)
						info.Coin = staking.Unit
						info.SumHold = staking.SumHold
						info.MaxHold = staking.MaxHold
						info.MinHold = staking.MinHold
						info.Period, _ = strconv.Atoi(staking.Period)
						info.Rate, _ = strconv.ParseFloat(strings.TrimRight(staking.Rate, "%"), 64)
						err = ppersistence.InsertStakingInfo(info)
						if err != nil {
							Error.Println(err)
						} else {
							//coin = staking.Unit
							//period, _ = strconv.Atoi(staking.Period)
							if info.Rate > float64(conf.NoticeRate) {
								bHasChanged = true
							}
							Info.Printf("NewCoin Staking: %v\n", info)
						}
					}
				}
			}
		}
	}
	if bHasChanged {
		//sms_send(coin, fmt.Sprintf("%v", period))
		sms_send(fmt.Sprintf("%v", rand.Intn(10000)), "3")
	}
}

func main() {
	rand.Seed(time.Now().Unix())
	t := time.NewTicker(time.Duration(conf.SpiderDuration) * time.Minute)
	wg := sync.WaitGroup{}
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			processActivityList()
			processStakingList()
			<-t.C
		}
	}()
	wg.Wait()
}
